﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SiteSettingRepository.cs" company="ecblog.codeplex.com">
//   emrecoskun.net - ibrahimatay.com
// </copyright>
// <summary>
//   The site setting repository
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace EcBlog.Data.Sql
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    using EcBlog.Data;
    using EcBlog.Data.Sql.Base;
    using EcBlog.Extensions;
    using EcBlog.Models;

    /// <summary>
    /// The site setting repository
    /// </summary>
    public class SiteSettingRepository : RepositoryWithHistory<SiteSetting, SiteSettingHistory>, ISiteSettingRepository
    {
        private const string CacheKey = "#ecBlog#SiteSettingKeys#";
        private static readonly object CacheLockObject = new object();

        /// <summary>
        /// Initializes a new instance of the <see cref="SiteSettingRepository"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        public SiteSettingRepository(EcModelContext context)
            : base(context)
        {
        }
        
        /// <summary>
        /// Gets the <see cref="System.String"/> with the specified site setting key.
        /// </summary>
        /// <param name="siteSettingKey">The site setting key</param>
        /// <returns>The setting value</returns>
        public string this[SiteSettingKey siteSettingKey]
        {
            get
            {
                var result = HttpRuntime.Cache[CacheKey] as List<SiteSetting>;
                if (result == null)
                {
                    lock (CacheLockObject)
                    {
                        result = HttpRuntime.Cache[CacheKey] as List<SiteSetting>;
                        if (result == null)
                        {
                            result = this.Get().ToList();
                            HttpRuntime.Cache.Insert(CacheKey, result, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
                        }
                    }
                }

                var key = Enum.GetName(typeof(SiteSettingKey), siteSettingKey);
                var setting = result.Where(c => c.SettingKey == key).Select(c => c.SettingValue).FirstOrDefault();
                return setting;
            }
        }

        public override void Create(SiteSetting entity)
        {
            this.EncryptValue(entity);
            base.Create(entity);
        }

        public override void Update(SiteSetting entityToUpdate)
        {
            this.EncryptValue(entityToUpdate);
            base.Update(entityToUpdate);
        }

        public override IQueryable<SiteSetting> Get(string includeProperties = "")
        {
            var list = base.Get(includeProperties).ToList();
            list.ForEach(c => list.ForEach(this.DecrpytValue));
            return list.AsQueryable();
        }

        public override IEnumerable<SiteSetting> GetWithRawSql(string query, params object[] parameters)
        {
            var list = base.GetWithRawSql(query, parameters).ToList();
            list.ForEach(this.DecrpytValue);
            return list.AsQueryable();
        }

        public override SiteSetting GetById(object id)
        {
            var result = base.GetById(id);
            this.DecrpytValue(result);
            return result;
        }

        private void EncryptValue(SiteSetting c)
        {
            if (c.SettingKey.ToLower().IndexOf("password", StringComparison.Ordinal) > -1)
            {
                c.SettingValue = c.SettingValue.Encrypt(MvcApplication.SharedSecret);
            }
        }

        private void DecrpytValue(SiteSetting c)
        {
            if (c.SettingKey.ToLower().IndexOf("password", StringComparison.Ordinal) == -1)
            {
                return;
            }

            try
            {
                if (c.SettingValue.IsBase64String())
                {
                    c.SettingValue = c.SettingValue.Decrypt(MvcApplication.SharedSecret);    
                }
                else
                {
                    this.Update(c);
                }
            }
            catch (System.Security.Cryptography.CryptographicException)
            {
                this.Update(c);
            }
            catch (FormatException)
            {
                this.Update(c);
            }
        }
    }
}